﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.IO;
using HostTool.Core;
using HostTool.Protocol;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace UpGrade
{
    public partial class Form_Main : Form
    {
        public Form_Main()
        {
            InitializeComponent();
        }
        //start---------------------------------------------------------------------------------
        CPU cpu;
        Thread threadUpload;

        const int UpateResetTime = 30;
        const int MTU = 512;
        const byte firmwareTypeType = 0x16;
        int[] showVerInner = new int[] { 0x10, 0x10, 0x10 }; //0x10-显示外部版本号 0x28-显示内部版本号

        private void ProcUpdateFirmware(object args)
        {
            string fileName = (string)args;

            #region//初始化进度条
            this.Invoke(new MethodInvoker(delegate
            {
                lbUpdateStatus.ForeColor = Color.Black;
                lbUpdateStatus.Text = "准备升级";
                pbUpdate.Value = 0;
            }));
            #endregion

            #region//读取程序文件
            if (File.Exists(fileName) == false)
            {
                this.Invoke(new MethodInvoker(delegate
                {
                    lbUpdateStatus.Text = "升级失败:文件不存在!";
                    lbUpdateStatus.ForeColor = Color.Red;
                    btUpload.Enabled = true;
                    buttonVersion.Enabled = true;
                }));
                return;
            }
            byte[] fileData = File.ReadAllBytes(fileName);
            #endregion

            #region//计算传输的帧个数
            int frameCnt = fileData.Length / MTU;       //帧总数
            int leftLength = fileData.Length % MTU;     //最后一帧长度（MTU为帧长度）

            if (leftLength > 0)
            {
                frameCnt++;
            }
            #endregion

            #region//升级控制帧数据
            int maxFrameNum = frameCnt - 1;//最大帧序号（从0开始）=帧总数-1
            byte[] frameTx = new byte[4];
            frameTx[0] = 0;                             //0-软件升级 1-文件下载 
            frameTx[1] = (byte)(maxFrameNum >> 8);
            frameTx[2] = (byte)(maxFrameNum & 0xff);
            frameTx[3] = firmwareTypeType;              //软件类型
            #endregion

            byte[] frameData = new byte[2 + MTU];
            bool resetOK = false;

            RequestPackage package;
            for (int i = 0; i < 3; i++)
            {
                #region//(1)复位
                package = cpu.CreateRequest(0x02, 0x08, 20);
                cpu.SendRequest(package);

                Frame frame = package.WaitResponse();

                if (frame != null)
                {
                }
                for (int j = 0; j < 5; j++)
                {
                    this.Invoke(new MethodInvoker(delegate
                    {
                        lbUpdateStatus.ForeColor = Color.Black;
                        lbUpdateStatus.Text = String.Format("等待CPU重启({0})秒...", 5 - j);
                    }));
                    Thread.Sleep(1000);
                }
                #endregion

                #region//(2)发送升级命令
                this.Invoke(new MethodInvoker(delegate
                {
                    lbUpdateStatus.Text = "发送升级命令";
                }));
                package = cpu.CreateRequest(0x03, 0x11, frameTx, frameTx.Length, 10000);
                cpu.SendRequest(package);
                frame = package.WaitResponse(); //等待6秒
                if (frame != null)
                {
                    int dOffset = frame.RealDataOffset;
                    if (frame.RawData[dOffset] == 0x11)
                    {
                        resetOK = true;
                        break;
                    }
                }
                #endregion
            }

            if (resetOK == false)
            {
                this.Invoke(new MethodInvoker(delegate
                {
                    lbUpdateStatus.Text = "升级失败:CPU复位失败!";
                    lbUpdateStatus.ForeColor = Color.Red;
                    btUpload.Enabled = true;
                    buttonVersion.Enabled = true;
                }));
                return;
            }
            //(3)发送固件数据
            int offset = 0;
            for (int i = 0; i < frameCnt; i++)
            {
                int txLen = cpu.MTU;
                if ((i == frameCnt - 1) && (leftLength > 0))
                {
                    txLen = leftLength;
                }

                bool sendOK = false;
                for (int j = 0; j < 10; j++)
                {
                    this.Invoke(new MethodInvoker(delegate
                    {
                        lbUpdateStatus.Text = String.Format("发送升级包第{0}次：({1}/{2})", j, i + 1, frameCnt);
                    }));

                    Array.Copy(fileData, offset, frameData, 2, txLen);
                    frameData[1] = (byte)(i >> 8); //帧序号
                    frameData[0] = (byte)(i & 0xff);
                    package = cpu.CreateRequest(0x03, 0x12, frameData, txLen + 2, 1500);

                    cpu.SendRequest(package);
                    Frame frame = package.WaitResponse();

                    if (frame != null)
                    {
                        int dOffset = frame.RealDataOffset;
                        if (frame.RawData[dOffset + 0] != frameData[0])
                        {
                            this.Invoke(new MethodInvoker(delegate
                            {
                                lbUpdateStatus.ForeColor = Color.Red;
                                lbUpdateStatus.Text = String.Format("错误数据包应答：({0}，{1}，{2})", frame.RawData[dOffset + 0],
                                                                                                        frame.RawData[dOffset + 1],
                                                                                                        frame.RawData[dOffset + 2]);
                            }));
                            Thread.Sleep(5000);
                            continue;
                        }

                        if (frame.RawData[dOffset + 1] != frameData[1])
                        {
                            this.Invoke(new MethodInvoker(delegate
                            {
                                lbUpdateStatus.ForeColor = Color.Red;
                                lbUpdateStatus.Text = String.Format("错误数据包应答：({0}，{1}，{2})", frame.RawData[dOffset + 0],
                                                                                                        frame.RawData[dOffset + 1],
                                                                                                        frame.RawData[dOffset + 2]);
                            }));
                            Thread.Sleep(5000);
                            continue;
                        }

                        if (frame.RawData[dOffset + 2] != 0)
                        {
                            this.Invoke(new MethodInvoker(delegate
                            {
                                lbUpdateStatus.ForeColor = Color.Red;
                                lbUpdateStatus.Text = String.Format("错误数据包应答：({0}，{1}，{2})", frame.RawData[dOffset + 0],
                                                                                                        frame.RawData[dOffset + 1],
                                                                                                        frame.RawData[dOffset + 2]);
                            }));
                            Thread.Sleep(5000);
                            continue;
                        }

                        sendOK = true;
                        offset += txLen;
                        this.Invoke(new MethodInvoker(delegate
                        {
                            pbUpdate.Value = pbUpdate.Maximum * (i + 1) / frameCnt;
                        }));
                        break;
                    }
                    else
                    {
                        this.Invoke(new MethodInvoker(delegate
                        {
                            lbUpdateStatus.Text = " NO 数据包应答！";
                            lbUpdateStatus.ForeColor = Color.Purple;
                        }));
                    }
                }

                if (sendOK == false)
                {
                    this.Invoke(new MethodInvoker(delegate
                    {
                        lbUpdateStatus.Text = "升级失败:发送升级数据包失败!";
                        lbUpdateStatus.ForeColor = Color.Red;
                        btUpload.Enabled = true;
                        buttonVersion.Enabled = true;
                    }));
                    return;
                }


            }

            //(4)等待应用程序启动
            bool updateResetOK = false;
            package = cpu.CreateRequest(0x03, 0x14, 2000);
            for (int i = 0; i < UpateResetTime; i++)
            {


                cpu.SendRequest(package);

                this.Invoke(new MethodInvoker(delegate
                {
                    lbUpdateStatus.Text = String.Format("查询升级状态({0}/{1})...", i + 1, UpateResetTime);

                }));

                Frame frame = package.WaitResponse();

                if (frame != null)
                {

                    if (frame.RawData[frame.RealDataOffset] == 0)
                    {
                        updateResetOK = true;

                        this.Invoke(new MethodInvoker(delegate
                        {
                            lbUpdateStatus.Text = "升级成功!";
                            lbUpdateStatus.ForeColor = Color.Green;
                            //MessageBox.Show("升级成功");
                            btUpload.Enabled = true;
                            buttonVersion.Enabled = true;
                        }));
                        break;
                    }
                }
                Thread.Sleep(1000);

            }
            if (updateResetOK == false)
            {
                this.Invoke(new MethodInvoker(delegate
                {
                    lbUpdateStatus.Text = "升级失败:查询升级状态失败!";
                    lbUpdateStatus.ForeColor = Color.Red;
                    //MessageBox.Show("升级成功");
                    btUpload.Enabled = true;
                    buttonVersion.Enabled = true;
                }));
            }

        }

        private void btUpload_Click(object sender, EventArgs e)
        {
            threadUpload = new Thread(new ParameterizedThreadStart(ProcUpdateFirmware));
            threadUpload.IsBackground = true;
            threadUpload.Start(tbFileLocation.Text);

            btUpload.Enabled = false;
            buttonVersion.Enabled = false;
        }
        
        private void button1_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog ofd = new OpenFileDialog())
            {
                ofd.Filter = "Hex文件|*.hex|BIN文件|*.bin|参数文件|*.txt";
                if (ofd.ShowDialog() == DialogResult.OK)
                {
                    tbFileLocation.Text = ofd.FileName;
                    btUpload.Enabled = true;
                    buttonVersion.Enabled = true;
                }
            }
        }

        private void buttonVersion_Click(object sender, EventArgs e)
        {

            tbBiosVersion.Clear();
            tbBiosDate.Clear();
            tbAppVersion.Clear();
            tbAppDate.Clear();

            RequestPackage package = cpu.CreateRequest(0x03, 0x09, 1000);

            package.CallbackHandler = new RequestCallbackHandler(ProcessVersion);
            cpu.SendRequest(package);

            RequestPackage packageInner = cpu.CreateRequest(0x03, 0x27, 2000); //发送0x27返回0x28 //内部版本号
            packageInner.CallbackHandler = new RequestCallbackHandler(ProcessVersion);
            cpu.SendRequest(packageInner);

        }
        
        private void ProcessVersion(Frame frame)
        {
            if (frame != null)
            {
                int cmd = frame.Cmd;
                this.Invoke(new MethodInvoker(delegate
                {

                    int N = frame.RealDataLength / 7;
                    byte[] data = frame.RawData;
                    int offset = frame.RealDataOffset;
                    for (int i = 0; i < N; i++)
                    {
                        //版本
                        StringBuilder sbVer = new StringBuilder("V");
                        string vers = data[offset + i * 7 + 1].ToString("X2");

                        sbVer.Append(vers[0] + "." + vers[1] + ".");
                        vers = data[offset + i * 7 + 2].ToString("X2");
                        sbVer.Append(vers[0] + "." + vers[1]);
                        StringBuilder sbTime = new StringBuilder();

                        sbTime.Append(data[offset + i * 7 + 3].ToString("X2"));
                        sbTime.Append(data[offset + i * 7 + 4].ToString("X2"));
                        sbTime.Append("年");


                        sbTime.Append(data[offset + i * 7 + 5].ToString("X2"));
                        sbTime.Append("月");
                        sbTime.Append(data[offset + i * 7 + 6].ToString("X2"));
                        sbTime.Append("日");
                        switch (data[offset + i * 7])
                        {
                            case 0:
                                if (showVerInner[0] == cmd)
                                {
                                    tbBiosVersion.Text = sbVer.ToString();
                                    tbBiosDate.Text = sbTime.ToString();
                                }
                                break;
                            case 1:
                                if (showVerInner[1] == cmd)
                                {
                                    tbAppVersion.Text = sbVer.ToString();
                                    tbAppDate.Text = sbTime.ToString();
                                }
                                break;
                            //case 2:
                            //    if (showVerInner[2] == cmd)
                            //    {
                            //        textBoxUSBVer.Text = sbVer.ToString();
                            //        textBoxUSBDate.Text = sbTime.ToString();
                            //    }
                            //    break;
                        }


                    }

                }));
            }
        }

        private void Form_Main_Load(object sender, EventArgs e)
        {
            HostMachine machine = MachineManager.GetMachine();

            machine.Start();
            foreach (IBoard board in machine.Boards)
            {
                foreach (ICPU cpu in board.CPUS)
                {
                    this.cpu = cpu as LinkBoardCPU;

                }
            }
        }

        private void Form_Main_FormClosing(object sender, FormClosingEventArgs e)
        {
            HostMachine machine = MachineManager.GetMachine();
            machine.FrameManager.RequesStop();
            MachineManager.CloseMachine();
        }








        //end-----------------------------------------------------------------------------------------
    }
}
